package com.fastwire.carriere.controller.impl;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import pegasus.eai.sgnmd.ws.ActReqDO;
import pegasus.eai.sgnmd.ws.MetroEInterface;
import pegasus.eai.sgnmd.ws.MetroE_WSLocator;

import com.fastwire.carriere.common.Messages;
import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.constant.OrderConstants;
import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.DateUtil;
import com.fastwire.carriere.common.util.StringUtil;
import com.fastwire.carriere.controller.ServiceOrderController;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.OrderDao;
import com.fastwire.carriere.pegasus.vo.PegasusOrderDetailsVo;
import com.fastwire.carriere.serviceorder.entity.ActivityStatus;
import com.fastwire.carriere.serviceorder.entity.ServiceOrder;
import com.fastwire.carriere.serviceorder.entity.ServiceOrderActivity;
import com.fastwire.carriere.serviceorder.vo.OrderSearchCriteriaVo;
import com.fastwire.carriere.serviceorder.vo.ServiceOrderVo;
import com.google.common.collect.Lists;

public class ServiceOrderControllerImpl implements ServiceOrderController {

	private final OrderDao orderDao = DAOFactory.getInstance().getOrderDao();

	@Override
	public void createServiceOrder(PegasusOrderDetailsVo orderDetailsVo)
			throws DAOException, ResourceException {

		List<ActivityStatus> ongoingActivities = orderDao
				.getWIPOrderActivitiesbyWorkOrderNo(orderDetailsVo
						.getWorkOrderNo());

		if (ongoingActivities != null && !ongoingActivities.isEmpty()) {
			throw new ResourceException(
					Messages.getString("message.common.order.orderisbeingprocessed.exception"));

		}
		ServiceOrder serviceOrder = orderDao
				.getServiceOrdersbyWorkOrderNo(orderDetailsVo.getWorkOrderNo());
		if (serviceOrder == null) {
			serviceOrder = new ServiceOrder(orderDetailsVo);
		} else {
			serviceOrder.update(orderDetailsVo);
		}
		orderDao.saveOrUpdate(serviceOrder);
	}

	@Override
	public List<ServiceOrderVo> searchServiceOrder(
			OrderSearchCriteriaVo searchCriteriaVo) throws DAOException {

		List<ServiceOrder> serviceOrders = orderDao
				.findServiceOrdersbySearchCriteria(searchCriteriaVo);
		List<ServiceOrderVo> serviceOrderVos = Lists.newArrayList();
		for (ServiceOrder serviceOrder : serviceOrders) {
			serviceOrderVos.add(new ServiceOrderVo(serviceOrder));
		}

		return serviceOrderVos;
	}

	@Override
	public void createServiceOrder(ServiceOrderVo serviceOrderVo)
			throws DAOException, ResourceException {

		ServiceOrder serviceOrder = orderDao
				.getServiceOrdersbyWorkOrderNo(serviceOrderVo.getWorkOrderNo());
		if (serviceOrder != null) {
			throw new ResourceException(Messages.getString(
					"message.common.order.ordernoadiexist.exception",
					new String[] { serviceOrderVo.getWorkOrderNo() }));
		}

		ServiceOrder newOrder = new ServiceOrder(serviceOrderVo);
		orderDao.saveOrUpdate(newOrder);
	}

	@Override
	public void performManualEBOD(ServiceOrderVo serviceOrderVo)
			throws DAOException, ResourceException {

		ServiceOrder serviceOrder = orderDao
				.getServiceOrdersbyWorkOrderNo(serviceOrderVo.getWorkOrderNo());
		if (serviceOrder != null) {
			serviceOrder.update(serviceOrderVo);

		} else {
			serviceOrder = new ServiceOrder(serviceOrderVo);

		}
		orderDao.saveOrUpdate(serviceOrder);

		processSingleOrder(serviceOrder, null, false);

	}

	@Override
	public void updateServiceOrder(ServiceOrderVo serviceOrderVo)
			throws DAOException, ResourceException {

		ServiceOrder serviceOrder = orderDao
				.getServiceOrdersbyWorkOrderNo(serviceOrderVo.getWorkOrderNo());
		if (serviceOrder == null) {
			throw new ResourceException(Messages.getString(
					"message.order.ordernotexist.exception",
					new String[] { serviceOrderVo.getWorkOrderNo() }));
		}
		serviceOrder.update(serviceOrderVo);

		orderDao.saveOrUpdate(serviceOrder);
	}

	@Override
	public void processPendingServiceOrders(Date date) throws DAOException,
			ResourceException {

		CommonLogger.info(this, "start provisioning");
		List<ServiceOrder> serviceOrders = orderDao.getServiceOrdersWithDueDate(date);

		List<String> orderIdList = Lists.newArrayList();

		for (ServiceOrder serviceOrder : serviceOrders) {
			orderIdList.add(serviceOrder.getWorkOrderNo());
		}

		List<ActivityStatus> activityStatuses = orderDao
				.getActivityStatusbyWorkOrders(orderIdList);

		for (ServiceOrder serviceOrder : serviceOrders) {

			processSingleOrder(serviceOrder, activityStatuses, true);

		}
	}

	private void provisionServiceOrder(ServiceOrder serviceOrder, ServiceOrderActivity activity)
	        throws DAOException, ResourceException 
	{
	    ActivityStatus activityStatus = new ActivityStatus(
				serviceOrder.getWorkOrderNo(), activity.getActivityNo());
        
		orderDao.saveOrUpdate(activityStatus);
	    
		try {
			String speed = serviceOrder
					.getPrdoductValue(OrderConstants.PRODUCT_INFO_SPEED);

			if (!StringUtil.isEmptyString(speed)) {

	            BandwidthControllerImpl bwController = new BandwidthControllerImpl();
	            CarPolicyControllerImpl carPolicyController = new CarPolicyControllerImpl();
				bwController.changeTunnelBandwidth(speed,
						serviceOrder.getServiceId(),
						AppConstants.ACTIVATION_TYPE_SERVICE);

				carPolicyController.modifyCarPolicy(
						serviceOrder.getServiceId(), Integer.valueOf(speed));

				activityStatus.handleComplete();

			} else {
				throw new ResourceException(Messages.getString(
						"message.order.productinfo.invalidparameter.exception",
						new String[] { OrderConstants.PRODUCT_INFO_SPEED,
								serviceOrder.getWorkOrderNo() }));
			}

		} catch (Throwable e) {
			e.printStackTrace();
			activityStatus.handleException(e.getMessage());
			throw new ResourceException(e.getMessage());
		} finally {
			orderDao.saveOrUpdate(activityStatus);
		}

	}

	private void processSingleOrder(ServiceOrder serviceOrder,
			List<ActivityStatus> activityStatuses, boolean isUpdatePegasus)
			throws DAOException, ResourceException {
		ActivityStatus orderActivityStatus = null;
		List<ServiceOrderActivity> activities = serviceOrder.getActivities();
		try {
			for (ServiceOrderActivity activity : activities) {
				if (OrderConstants.CEBS_ACTIVITIES.contains(activity
						.getActivityName())
						&& OrderConstants.ACTIVITY_STATUS_RDY.equals(activity
								.getActivityStatus())) {

					boolean isProvsioning = true;

					if (activityStatuses != null) {
						for (ActivityStatus activityStatus : activityStatuses) {

							if (activityStatus.getActivityNo().equals(
									activity.getActivityNo())
									&& activityStatus.getWorkOrderNo().equals(
											serviceOrder.getWorkOrderNo())) {
								isProvsioning = false;
								break;
							}
						}
					} else {
						/*CommonLogger.info(this,
								"The order" + serviceOrder.getWorkOrderNo()
										+ " is at 'COM' status, skipping");*/					
						CommonLogger.info(this, "No activity status");
					}

					if (isProvsioning
							&& !isAllPredecessorTaskCOM(activities,
									activity.getPredecessorList())) {
						isProvsioning = false;
					} else {
						// delete this on 20120419
						/*
						CommonLogger
								.info(this,
										"The order"
												+ serviceOrder.getWorkOrderNo()
												+ " cannot be provisioned the order because its predecessor activities have not been completed");
						*/
					}

					if (isProvsioning) {
						//  update the activity status first
						//and perform provisioning 
						orderActivityStatus = new ActivityStatus(
								serviceOrder.getWorkOrderNo(),
								activity.getActivityNo());
						orderDao.saveOrUpdate(orderActivityStatus);  // should remove this ??? 
						provisionServiceOrder(serviceOrder, activity);
						orderActivityStatus.handleComplete();

					}

				}
				else {
					CommonLogger.info(this,
							"The order" + serviceOrder.getWorkOrderNo()
									+ " is not at 'RDY' status, skipping");				
				}
			}
		} catch (Throwable e) {

			if (orderActivityStatus != null)
				orderActivityStatus.handleException(e.getMessage());
			throw new ResourceException(e.getMessage());
		} finally {
			if (orderActivityStatus != null) {
				orderDao.saveOrUpdate(orderActivityStatus);

				if (isUpdatePegasus)
					updatePegasus(orderActivityStatus);
			}

		}

	}

	private boolean isAllPredecessorTaskCOM(
			List<ServiceOrderActivity> activities, String predecessorListStr) {

		boolean flag = true;
		if (!StringUtil.isEmptyString(predecessorListStr)) {
			List<String> predecessorList = Arrays.asList(predecessorListStr
					.split(","));

			for (String activityNo : predecessorList) {
				for (ServiceOrderActivity activity : activities) {
					if (activity.getActivityNo().equals(activityNo)
							&& !activity.getActivityStatus().equals(
									OrderConstants.ACTIVITY_STATUS_COM)) {

						flag = false;
						break;
					}
				}

				if (!flag) {
					break;
				}

			}
		}

		return flag;

	}

	public void updatePegasus(ActivityStatus activityStatus)
			throws ResourceException {
		MetroE_WSLocator locator = new MetroE_WSLocator();
		ActReqDO reqDO = new ActReqDO();
		reqDO.setActNo(Integer.valueOf(activityStatus.getActivityNo()));
		reqDO.setWorkOrdNo(activityStatus.getWorkOrderNo());
		reqDO.setCompletedDt(DateUtil.formatDate(DateUtil.DATE_SLASH,
				activityStatus.getCompletedDate()));
		reqDO.setDelayReason(activityStatus.getDelayReason());
		reqDO.setStatusCd(activityStatus.getStatusCd());
		try {
			MetroEInterface metroEInterface = locator
					.getProjects_SgnMd_initial_AsMetroEEss_pegasus_eai_sgnmd_server_AsMetroEEss_MetroE_WS();

			metroEInterface.updateActStatus(reqDO);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new ResourceException(e.getMessage());
		}
	}
}
